package org.anachronos.jeep.model.trace.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.anachronos.jeep.model.trace.Invocation;
import org.anachronos.jeep.model.trace.MethodInvocation;
import org.anachronos.jeep.model.trace.Method;
import org.anachronos.jeep.model.trace.SqlStatementExecution;
import org.anachronos.jeep.model.trace.ThreadCallStack;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;


public class BacktraceMapBuilder {	
	public static class KeyGenerator extends TraceSwitch<String> {

		@Override
		public String caseMethodInvocation(final MethodInvocation methodInvocation) {
			final Method method = methodInvocation.getMethod();
			return method.getName();
		}

		@Override
		public String caseSqlStatementExecution(final SqlStatementExecution sqlStatementExecution) {
			return sqlStatementExecution.getStatement();
		}
	}

	private class BacktraceGenerator extends TraceSwitch<Boolean> {
		private final Map<String, List<Invocation>> backTraceMap = 
			new HashMap<String, List<Invocation>>();
		private final KeyGenerator keyGenerator = new KeyGenerator();

		@Override
		public Boolean caseInvocation(final Invocation invocation) {
			addToBackTraceMap(invocation);
			return true;
		}

		public Map<String, List<Invocation>> getBackTraceMap() {
			return backTraceMap;
		}

		private void addToBackTraceMap(final Invocation invocation) {
			final String key = keyGenerator.doSwitch(invocation);
			if (key != null) {
				List<Invocation> backTraces = backTraceMap.get(key);
				if (backTraces == null) {
					backTraces = new ArrayList<Invocation>();
					backTraceMap.put(key, backTraces);
				}
				final Invocation parentInvocation = 
					(Invocation) invocation.eContainer();
				backTraces.add(parentInvocation);
			}
		}
	}

	public Map<String, List<Invocation>> build(final ThreadCallStack threadCallStack) {
		final BacktraceGenerator backTraceGenerator = new BacktraceGenerator();
		final TreeIterator<EObject> allContents = threadCallStack.eAllContents();
		while (allContents.hasNext()) {
			final EObject next = allContents.next();
			backTraceGenerator.doSwitch(next);
		}
		return backTraceGenerator.getBackTraceMap();
	}
}
